package io.jt808.proto.req;

import io.norland.annotations.Proto;
import io.jt808.proto.item.PositionAdditionalItem;
import io.norland.buffer.AutoBuffer;
import io.norland.proto.IProto;
import io.jt808.util.Tools;
import lombok.Data;
import org.apache.log4j.Logger;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 位置信息汇报
 */
@Proto("0200")
@Data
public class JT0200 implements IProto {
    private static Logger logger = Logger.getLogger(JT0200.class);
    /**
     * 报警标志
     */
    private int alarmFlag;
    /**
     * 状态
     */
    private int status;
    /**
     * 纬度,以度为单位的纬度值乘以10的6次方，精确到百万分之一度
     */
    private double latitude;
    /**
     * 经度,以度为单位的经度值乘以10的6次方，精确到百万 分之一度
     */
    private double longitude;
    /**
     * 海拔高度，单位为米（m）
     */
    private short altitude;
    /**
     * 速度,1/10km/h
     */
    private double speed;
    /**
     * 方向,0～359，正北为0，顺时针
     */
    private short direction;
    /**
     * 时间,YY-MM-DD-hh-mm-ss（GMT+8时间，本标准中之后涉及的时间均采用此时区）
     */
    private Date time;

    private ArrayList<PositionAdditionalItem> additionals;

    private static Map<Integer, String> alarmTypeMap = new HashMap<>();

    static {
        alarmTypeMap.put(0, "紧急报警");
        alarmTypeMap.put(1, "超速报警");
        alarmTypeMap.put(2, "疲劳驾驶");
        alarmTypeMap.put(3, "危险预警");
        alarmTypeMap.put(4, "GNSS 模块发生故障");
        alarmTypeMap.put(5, "GNSS 天线未接或被剪断");
        alarmTypeMap.put(6, "GNSS 天线短路");
        alarmTypeMap.put(7, "终端主电源欠压");
        alarmTypeMap.put(8, "终端主电源掉电");
        alarmTypeMap.put(9, "终端 LCD 或显示器故障");
        alarmTypeMap.put(10, "TTS 模块故障");
        alarmTypeMap.put(11, "摄像头故障");
        alarmTypeMap.put(12, "道路运输证 IC 卡模块故障");
        alarmTypeMap.put(13, "超速预警");
        alarmTypeMap.put(14, "疲劳驾驶预警");
//        alarmTypeMap.put(15, "紧急报警");
//        alarmTypeMap.put(16, "紧急报警");
//        alarmTypeMap.put(17, "紧急报警");
        alarmTypeMap.put(18, "当天累计驾驶超时");
        alarmTypeMap.put(19, "超时停车");
        alarmTypeMap.put(20, "进出区域");
        alarmTypeMap.put(21, "进出路线");
        alarmTypeMap.put(22, "路段行驶时间不足/过长");
        alarmTypeMap.put(23, "路线偏离报警");
        alarmTypeMap.put(24, "车辆 VSS 故障");
        alarmTypeMap.put(25, "车辆油量异常");
        alarmTypeMap.put(26, "车辆被盗(通过车辆防盗器)");
        alarmTypeMap.put(27, "车辆非法点火");
        alarmTypeMap.put(28, "车辆非法位移");
        alarmTypeMap.put(29, "碰撞预警");
        alarmTypeMap.put(30, "侧翻预警");
        alarmTypeMap.put(31, "非法开门报警");
    }

    public final byte[] writeToBytes() {

        AutoBuffer buff = new AutoBuffer();
        buff.writeInt(alarmFlag);
        buff.writeInt(status);
        buff.writeInt((int) (latitude * 1000000.0));
        buff.writeInt((int) (longitude * 1000000.0));
        buff.writeShort(altitude);
        buff.writeShort((short) (speed * 10.0));
        buff.writeShort(direction);

        LocalDateTime localDateTime = LocalDateTime.ofInstant(time.toInstant(), ZoneId.systemDefault());
        String bcdString = Tools.getBcd(localDateTime.getYear() - 2000,
                localDateTime.getMonthValue(),
                localDateTime.getDayOfMonth(),
                localDateTime.getHour(),
                localDateTime.getMinute(),
                localDateTime.getSecond());
        buff.writeBcdString(bcdString, 6);

        for (PositionAdditionalItem ad : additionals)
            buff.writeBytes(ad.writeToBytes());

        return buff.array();
    }

    public final void readFromBuf(AutoBuffer buff) {
        alarmFlag = buff.readInt();
        status = buff.readInt();
        latitude = buff.readInt() / 1000000.0;
        longitude = buff.readInt() / 1000000.0;
        altitude = buff.readShort();
        speed = buff.readShort() / 10.0;
        direction = buff.readShort();
        Integer year = Integer.valueOf(buff.readBcd()) + 2000;
        Integer month = Integer.valueOf(buff.readBcd());
        Integer day = Integer.valueOf(buff.readBcd());
        Integer hour = Integer.valueOf(buff.readBcd());
        Integer minute = Integer.valueOf(buff.readBcd());
        Integer second = Integer.valueOf(buff.readBcd());
        time = getDate(year, month, day, hour, minute, second);

        additionals = new ArrayList<>();
        while (buff.isReadable()) {
            PositionAdditionalItem item = new PositionAdditionalItem();
            item.readFromBuf(buff);
            additionals.add(item);
        }
    }

    private Date getDate(Integer year, Integer month, Integer day, Integer hour, Integer minute, Integer second) {
        LocalDateTime localDateTime = LocalDateTime.of(year, month, day, hour, minute, second);
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = localDateTime.atZone(zoneId);
        return Date.from(zdt.toInstant());
    }

    public String getAlarmType() {
        return alarmTypeMap.get(alarmFlag);
    }

    /**
     * 是否打开ACC
     */
    public boolean isOpenAcc() {
        return (status & 1) != 0;
    }

    /**
     * 是否定位
     */
    public boolean isLocation() {
        return (status & 1 << 1) != 0;
    }

    /**
     * 是否北纬
     */
    public boolean isNorthLatitude() {
        return (status & 1 << 2) == 0;
    }

    /**
     * 是否西经
     */
    public boolean isEastLongitude() {
        return (status & 1 << 3) == 0;
    }

    /**
     * 是否运营状态
     */
    public boolean isOperate() {
        return (status & 1 << 4) == 0;
    }

    /**
     * 是否经纬度经保密插件加密
     */
    public boolean isEncrypted() {
        return (status & 1 << 5) != 0;
    }

    /**
     * 可用于客车的空、重车及货车的空载、满载状态表示，人工输入或传感器
     * 获取
     */
    public String getCarStatus() {
        int s = (status >> 8) & 0x03;
        switch (s) {
            case 0:
                return "empty";
            case 1:
                return "halfLoaded";
            default:// 3
                return "fullLoaded";
        }
    }

    /**
     * 是否车辆油路正常
     */
    public boolean isOilWayNormal() {
        return (status & 1 << 10) == 0;
    }

    /**
     * 是否车辆电路正常
     */
    public boolean isElectricCircuitNormal() {
        return (status & 1 << 11) == 0;
    }

    /**
     * 是否车门解锁
     */
    public boolean isDoorUnlock() {
        return (status & 1 << 12) == 0;
    }

    /**
     * 是否前门开
     */
    public boolean isFrontDoorOpen() {
        return (status & 1 << 13) != 0;
    }

    /**
     * 是否中门开
     */
    public boolean isMiddleDoorOpen() {
        return (status & 1 << 14) != 0;
    }

    /**
     * 是否后门开
     */
    public boolean isBackDoorOpen() {
        return (status & 1 << 15) != 0;
    }

    /**
     * 是否驾驶席门开
     */
    public boolean isDriverDoorOpen() {
        return (status & 1 << 16) != 0;
    }

    /**
     * 是否XX门开
     */
    public boolean isXXDoorOpen() {
        return (status & 1 << 17) != 0;
    }

    /**
     * 是否使用GPS
     */
    public boolean isUsingGPS() {
        return (status & 1 << 18) != 0;
    }

    /**
     * 是否使用北斗
     */
    public boolean isUsingBeiDou() {
        return (status & 1 << 19) != 0;
    }

    /**
     * 是否使用GLONASS
     */
    public boolean isUsingGLONASS() {
        return (status & 1 << 20) != 0;
    }

    /**
     * 是否使用Galileo
     */
    public boolean isUsingGalileo() {
        return (status & 1 << 21) != 0;
    }

//    public static void main(String[] args) {
//        String hex = "000000000000000301595e3206bcfd58000002940000181024141936010400011abb";
//        byte[] bytes = Tools.HexString2Bytes(hex);
//        AutoBuffer buffer = new AutoBuffer(bytes);
//        JT0200 jt0200 = new JT0200();
//        jt0200.readFromBuf(buffer);
//        System.out.println(jt0200.getAlarmType());
//        System.out.println(jt0200.isBackDoorOpen());
//        System.out.println(jt0200.getCarStatus());
////        System.out.println(Tools.ToHexFormatString(bytes));
////        System.out.println(Tools.ToHexFormatString(jt0200.writeToBytes()));
//    }
}